home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / mint / shells / bashsrc.zoo / jobs.c < prev    next >
C/C++ Source or Header  |  1991-06-05  |  41KB  |  1,722 lines

  1. /* The thing that makes children, remembers them, and contains wait loops. */
  2.  
  3. /* Copyright (C) 1989 Free Software Foundation, Inc.
  4.  
  5. This file is part of GNU Bash, the Bourne Again SHell.
  6.  
  7. Bash is free software; you can redistribute it and/or modify it under
  8. the terms of the GNU General Public License as published by the Free
  9. Software Foundation; either version 1, or (at your option) any later
  10. version.
  11.  
  12. Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  13. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License along
  18. with Bash; see the file COPYING.  If not, write to the Free Software
  19. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  20.  
  21. /* Something that can be ignored. */
  22. #define IGNORE_ARG (char *)0
  23.  
  24. #include "config.h"
  25.  
  26. #ifndef JOB_CONTROL
  27. #include "nojobs.c"
  28. #else
  29.  
  30. #include <stdio.h>
  31. #include <signal.h>
  32. #include <errno.h>
  33. #include <sys/types.h>
  34.  
  35. #include <sys/time.h>
  36. #include <sys/resource.h>
  37. #include <sys/file.h>
  38.  
  39. #include <fcntl.h>
  40. #include <sys/ioctl.h>
  41. #include <sys/param.h>
  42.  
  43. /* Terminal handling stuff, to save and restore tty state. */
  44. #define NEW_TTY_DRIVER
  45.  
  46. #if defined(SYSV) || defined(hpux) || defined(ALTOS)
  47. #undef NEW_TTY_DRIVER
  48. #endif /* SYSV || hpux || ALTOS */
  49.  
  50. #ifdef NEW_TTY_DRIVER
  51. #include <sgtty.h>
  52. #else
  53. #include <termio.h>
  54. #endif /* NEW_TTY_DRIVER */
  55.  
  56. /* For the TIOCGPGRP and TIOCSPGRP ioctl parameters on HP-UX */
  57.  
  58. #ifdef hpux
  59. #include <bsdtty.h>
  60. #endif /* hpux */
  61.  
  62. #include "shell.h"
  63. #include "jobs.h"
  64.  
  65. /* Not all systems define errno in errno.h. */
  66. extern int errno;
  67.  
  68. #ifndef sigmask
  69. #define sigmask(x) (1 << ((x)-1))
  70. #endif
  71.  
  72. #ifndef SIGABRT
  73. #define SIGABRT SIGIOT
  74. #endif
  75.  
  76. #ifndef SIGCHLD
  77. #define SIGCHLD SIGCLD
  78. #endif
  79.  
  80. /* The array of known jobs. */
  81. JOB **jobs = (JOB **)NULL;
  82.  
  83. /* The number of slots currently allocated to JOBS. */
  84. int job_slots = 0;
  85.  
  86. /* The number of additional slots to allocate when we run out. */
  87. #define JOB_SLOTS 5
  88.  
  89. /* The controlling tty for this shell. */
  90. int shell_tty;
  91.  
  92. /* The shell's process group. */
  93. int shell_pgrp = -1;
  94.  
  95. /* The terminal's process group. */
  96. int terminal_pgrp = -1;
  97.  
  98. /* The process group of the shell's parent. */
  99. int original_pgrp = -1;
  100.  
  101. /* The process group of the pipeline currently being made. */
  102. int pipeline_pgrp = 0;
  103.  
  104. /* The job which is current; i.e. the one that `%+' stands for. */
  105. int current_job = NO_JOB;
  106.  
  107. /* The previous job; i.e. the one that `%-' stands for. */
  108. int previous_job = NO_JOB;
  109.  
  110. /* Last child made by the shell.  */
  111. int last_made_pid = -1;
  112.  
  113. /* Pid of the last asynchronous child. */
  114. int last_asynchronous_pid = -1;
  115.  
  116. /* Non-zero allows asynchronous job notification.  If not set,
  117.    then job state notification only takes place just before a
  118.    prompt is printed. */
  119. int asynchronous_notification = 0;
  120.  
  121. #ifndef hpux
  122. /* The total amount of system time spent running processes for me. */
  123. struct timeval total_systime = {0, 0};
  124. long system_minutes_used = 0;
  125. int system_seconds_used = 0;
  126.  
  127. /* The total amount of user time spent running processes for me. */
  128. struct timeval total_usertime = {0, 0};
  129. long user_minutes_used = 0;
  130. int user_seconds_used = 0;
  131. #endif /* hpux */
  132.  
  133. /* The pipeline currently being built. */
  134. PROCESS *the_pipeline = (PROCESS *)NULL;
  135.  
  136. /* If this is non-zero, do job control. */
  137. int job_control = 1;
  138.  
  139. /* Call this when you start making children. */
  140. int already_making_children = 0;
  141.  
  142. /* These are definitions to map POSIX 1003.1 functions onto existing BSD
  143.    library functions and system calls. */
  144.  
  145. #define setpgid(pid, pgrp)    setpgrp (pid, pgrp)
  146. #define tcsetpgrp(fd, pgrp)    ioctl ((fd), TIOCSPGRP, &(pgrp))
  147.  
  148. tcgetpgrp (fd)
  149.      int fd;
  150. {
  151.   int pgrp;
  152.  
  153.   /* ioctl will handle setting errno correctly. */
  154.   if (ioctl (fd, TIOCGPGRP, &pgrp) < 0)
  155.     return (-1);
  156.   return (pgrp);
  157. }
  158.  
  159. /* END of POISX 1003.1 definitions. */
  160.  
  161. making_children ()
  162. {
  163.   if (already_making_children)
  164.     return;
  165.  
  166.   already_making_children = 1;
  167.   start_pipeline ();
  168. }
  169.  
  170. stop_making_children ()
  171. {
  172.   already_making_children = 0;
  173. }
  174.  
  175. /* Start building a pipeline.  */
  176. start_pipeline ()
  177. {
  178.   if (the_pipeline)
  179.     {
  180.       discard_pipeline (the_pipeline);
  181.       the_pipeline = (PROCESS *)NULL;
  182.       pipeline_pgrp = 0;
  183.     }
  184. }
  185.  
  186. /* Stop building a pipeline.  Install the process list in the job array.
  187.    This returns the index of the newly installed job.
  188.    DEFERRED is a command structure to be executed upon satisfactory
  189.    execution exit of this pipeline. */
  190. int
  191. stop_pipeline (async, deferred)
  192.      int async;
  193.      COMMAND *deferred;
  194. {
  195.   register int i, j;
  196.   int oldmask;
  197.   JOB *newjob = (JOB *)NULL;
  198.   char *get_string_value ();
  199.  
  200.   oldmask = sigblock (sigmask (SIGCHLD));
  201.  
  202.   cleanup_dead_jobs ();
  203.  
  204.   if (!job_slots)
  205.     {
  206.       jobs =
  207.     (JOB **)xmalloc ((1 + (job_slots = JOB_SLOTS)) * sizeof (JOB *));
  208.  
  209.       /* Now blank out these new entries. */
  210.       for (i = 0; i < job_slots; i++)
  211.     jobs[i] = (JOB *)NULL;
  212.     }
  213.  
  214.   /* Scan from the last slot backward, looking for the next free one. */
  215.   for (i = job_slots; i; i--)
  216.     if (jobs[i - 1])
  217.       break;
  218.  
  219.   /* Do we need more room? */
  220.   if (i == job_slots)
  221.     {
  222.       jobs = (JOB **)realloc
  223.     (jobs, (1 + (job_slots += JOB_SLOTS)) * sizeof (JOB *));
  224.  
  225.       for (j = i; j < job_slots; j++)
  226.     jobs[j] = (JOB *)NULL;
  227.     }
  228.  
  229.   /* Add the current pipeline to the job list. */
  230.   if (the_pipeline)
  231.     {
  232.       extern int errno, sys_nerr;
  233.       extern char *sys_errlist[];
  234.       register PROCESS *p;
  235.  
  236.       newjob = (JOB *)xmalloc (sizeof (JOB));
  237.  
  238.       for (p = the_pipeline; p->next != the_pipeline; p = p->next);
  239.       p->next = (PROCESS *)NULL;
  240.       newjob->pipe = (PROCESS *)reverse_list (the_pipeline);
  241.       for (p = newjob->pipe; p->next; p = p->next);
  242.       p->next = newjob->pipe;
  243.  
  244.       the_pipeline = (PROCESS *)NULL;
  245.       newjob->pgrp = pipeline_pgrp;
  246.       pipeline_pgrp = 0;
  247.  
  248.       /* Flag to see if in another pgrp. */
  249.       newjob->job_control = job_control;
  250.  
  251.       /* Set the state of this pipeline. */
  252.       {
  253.     register PROCESS *p = newjob->pipe;
  254.     register int any_alive = 0;
  255.     register int any_stopped = 0;
  256.  
  257.     do
  258.       {
  259.         any_alive |= p->running;
  260.         any_stopped |= WIFSTOPPED (p->status);
  261.         p = p->next;
  262.       }
  263.     while (p != newjob->pipe);
  264.  
  265.     if (any_alive)
  266.       {
  267.         newjob->state = JRUNNING;
  268.       }
  269.     else
  270.       {
  271.         if (any_stopped)
  272.           newjob->state = JSTOPPED;
  273.         else
  274.           newjob->state = JDEAD;
  275.       }
  276.       }
  277.  
  278.       newjob->notified = 0;
  279.  
  280.       newjob->wd = get_string_value ("PWD");
  281.  
  282.       if (newjob->wd)
  283.     newjob->wd = savestring (newjob->wd);
  284.       else
  285.     newjob->wd = (char *)get_working_directory ("");
  286.  
  287.       if (!(newjob->wd))
  288.     newjob->wd = savestring ("<no directory>");
  289.  
  290.       newjob->deferred = deferred;
  291.  
  292.       jobs[i] = newjob;
  293.     }
  294.  
  295.   if (async)
  296.     {
  297.       if (newjob)
  298.     newjob->foreground = 0;
  299.       reset_current ();
  300.     }
  301.   else
  302.     {
  303.       if (newjob)
  304.     {
  305.       newjob->foreground = 1;
  306.       /*
  307.        *            !!!!! NOTE !!!!!  (chet@ins.cwru.edu)
  308.        *
  309.        * The currently-accepted job control wisdom says to set the
  310.        * terminal's process group n+1 times in an n-step pipeline:
  311.        * once in the parent and once in each child.  This is where
  312.        * the parent gives it away.
  313.        *
  314.        */
  315.       if (job_control && pipeline_pgrp)
  316.         give_terminal_to (pipeline_pgrp);
  317.     }
  318.     }
  319.  
  320.   stop_making_children ();
  321.   sigsetmask (oldmask);
  322.   return (current_job);
  323. }
  324.  
  325. /* Delete all DEAD jobs that the user had received notification about. */
  326. cleanup_dead_jobs ()
  327. {
  328.   int oldmask = sigblock (sigmask (SIGCHLD));
  329.   register int i;
  330.  
  331.   for (i = 0; i < job_slots; i++)
  332.     if (jobs[i] && JOBSTATE (i) == JDEAD && jobs[i]->notified)
  333.       delete_job (i);
  334.  
  335.   sigsetmask (oldmask);
  336. }
  337.  
  338. /* Delete the job at INDEX from the job list. */
  339. delete_job (index)
  340.      int index;
  341. {
  342.   register JOB *temp = jobs[ind